/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-06-10     liuduanfei   first version
 */

#include <rtthread.h>
#include <rtdevice.h>
#include <rtservice.h>
#include <board.h>

//#define DRV_I2C_DEBUG

#define DBG_TAG "i2c"

#ifdef DRV_I2C_DEBUG

#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO

#endif /* DRV_I2C_DEBUG */
#include <rtdbg.h>

#ifdef BSP_USING_I2C

#if !defined(BSP_USING_I2C1) && !defined(BSP_USING_I2C2) && !defined(BSP_USING_I2C3)
#error "Please define at least one BSP_USING_I2Cx"
#endif

#define TIMEOUT          (0x10000ul)

struct hc_i2c
{
    const char *name;
    M4_I2C_TypeDef* I2Cx;
    struct rt_i2c_bus_device bus; 
};

enum
{
#ifdef BSP_USING_I2C1
    I2C1_INDEX,
#endif
#ifdef BSP_USING_I2C2
    I2C2_INDEX,
#endif
#ifdef BSP_USING_I2C3
    I2C3_INDEX,
#endif
};

struct hc_i2c i2c_obj[] =
{
#ifdef BSP_USING_I2C1
    {.name = "i2c1", .I2Cx = M4_I2C1},
#endif
#ifdef BSP_USING_I2C2
    {.name = "i2c2", .I2Cx = M4_I2C2},
#endif
#ifdef BSP_USING_I2C3
    {.name = "i2c3", .I2Cx = M4_I2C3},
#endif
};

rt_uint32_t i2c_num = (sizeof(i2c_obj) / sizeof(i2c_obj[0]));

rt_err_t hc_i2c_init(M4_I2C_TypeDef* I2Cx, rt_uint32_t baudrate)
{
    en_result_t enRet;
    stc_i2c_init_t stcI2cInit;
    float32_t fErr;
    
    i2c_ll_init(I2Cx);

    I2C_DeInit(I2Cx);

    MEM_ZERO_STRUCT(stcI2cInit);
    stcI2cInit.u32ClockDiv = I2C_CLK_DIV2;
    stcI2cInit.u32Baudrate = baudrate;
    stcI2cInit.u32SclTime = 0ul;

    enRet = I2C_Init(I2Cx, &stcI2cInit, &fErr);
    if (enRet != Ok)
    {
        return -RT_EIO;
    }

    I2C_BusWaitCmd(I2Cx, Enable);

    I2C_Cmd(I2Cx, Enable);
    I2C_SoftwareResetCmd(I2Cx, Enable);
    I2C_SoftwareResetCmd(I2Cx, Disable);

    return RT_EOK;
}

static void hc_i2c_reset(M4_I2C_TypeDef* I2Cx)
{
    I2C_SoftwareResetCmd(I2Cx, Enable);
    I2C_SoftwareResetCmd(I2Cx, Disable);
}

static rt_err_t hc_i2c_restart(M4_I2C_TypeDef* I2Cx)
{
    en_result_t enRet;
    enRet = I2C_Restart(I2Cx, TIMEOUT);
    if(Ok != enRet)
    {
        return -RT_ETIMEOUT;
    }
    return RT_EOK;
}

static rt_err_t hc_i2c_start(M4_I2C_TypeDef* I2Cx)
{
    en_result_t enRet;
    enRet = I2C_Start(I2Cx, TIMEOUT);
    if(Ok != enRet)
    {
        return -RT_ETIMEOUT;
    }
    return RT_EOK;
}

static rt_err_t hc_i2c_send_address(M4_I2C_TypeDef* I2Cx,
                                    struct rt_i2c_msg *msg)
{
    en_result_t enRet;
    en_trans_direction_t enDir;
    if (msg->flags & RT_I2C_RD)
    {
        enDir = I2CDirReceive;
    }
    else
    {
        enDir = I2CDirTrans;
    }
    
    enRet = I2C_TransAddr(I2Cx, msg->addr, enDir, TIMEOUT);
    if (enRet == ErrorTimeout)
    {
        return -RT_ETIMEOUT;
    }
    if (enRet == Error)
    {
        return -RT_ERROR;
    }
    return RT_EOK;
}

static rt_err_t hc_i2c_stop(M4_I2C_TypeDef* I2Cx)
{
    en_result_t enRet;
    enRet = I2C_Stop(I2Cx, TIMEOUT);
    if (enRet != Ok)
    {
        return -RT_ERROR;
    }
    return RT_EOK;
}

static rt_err_t hc_i2c_send_bytes(M4_I2C_TypeDef* I2Cx,
                                  struct rt_i2c_msg *msg)
{
    en_result_t enRet;
    enRet = I2C_TransData(I2Cx, msg->buf, msg->len, TIMEOUT);
    if (enRet == Ok)
    {
        return msg->len;
    }
    else
    {
        return 0;
    }
}

static rt_err_t hc_i2c_recv_bytes(M4_I2C_TypeDef* I2Cx,
                                  struct rt_i2c_msg *msg)
{
    en_result_t enRet;
    if(1ul == msg->len)
    {
        I2C_AckConfig(I2Cx, I2c_NACK);
    }
    enRet = I2C_ReceiveData(I2Cx, msg->buf, msg->len, TIMEOUT);
    if (enRet == Ok)
    {
        return msg->len;
    }
    else
    {
        return 0;
    }
}

static rt_size_t master_xfer(struct rt_i2c_bus_device *bus,
                             struct rt_i2c_msg msgs[],
                             rt_uint32_t num)
{
    struct rt_i2c_msg *msg;
    rt_int32_t i, ret;
    rt_uint16_t ignore_nack;
    struct hc_i2c * i2c;

    i2c = rt_container_of(bus, struct hc_i2c, bus);

    if (num == 0) return 0;
    
    for (i = 0; i < num; i++)
    {
        msg = &msgs[i];
        ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
        if (!(msg->flags & RT_I2C_NO_START))
        {
            if (i)
            {
                LOG_D("send restart condition");
                hc_i2c_restart(i2c->I2Cx);
                if (ret != RT_EOK)
                {
                    LOG_D("send restart condition failed");
                    goto out;
                }
            }
            else
            {
                LOG_D("send start condition");
                ret = hc_i2c_start(i2c->I2Cx);
                if ((ret != RT_EOK) && !ignore_nack)
                {
                    LOG_D("send start condition failed");
                    goto out;
                }
            }
            ret = hc_i2c_send_address(i2c->I2Cx, msg);
            if ((ret == -RT_ERROR) && !ignore_nack)
            {
                LOG_D("receive NACK from device addr 0x%02x msg %d",
                        msgs[i].addr, i);
                goto out;
            }
            else if (ret == -RT_ETIMEOUT)
            {
                LOG_D("send i2c address timeout");
                goto out;
            }
        }
        if (msg->flags & RT_I2C_RD)
        {
            ret = hc_i2c_recv_bytes(i2c->I2Cx, msg);
            if (ret >= 1)
                LOG_D("read %d byte%s", ret, ret == 1 ? "" : "s");
            if (ret < msg->len)
            {
                if (ret >= 0)
                    ret = -RT_EIO;
                goto out;
            }
        }
        else
        {
            ret = hc_i2c_send_bytes(i2c->I2Cx, msg);
            if (ret >= 1)
                LOG_D("write %d byte%s", ret, ret == 1 ? "" : "s");
            if (ret < msg->len)
            {
                if (ret >= 0)
                    ret = -RT_ERROR;
                goto out;
            }
        }
    }
out:
    if (!(msg->flags & RT_I2C_NO_STOP))
    {
        LOG_D("send stop condition");
        ret = hc_i2c_stop(i2c->I2Cx);
        if (ret != RT_EOK)
        {
            LOG_D("send i2c stop timeout");
            ret = 0;
        }
    }

    return (ret == RT_EOK)? i: ret;
}

static rt_size_t slave_xfer(struct rt_i2c_bus_device *bus,
                        struct rt_i2c_msg msgs[],
                        rt_uint32_t num)
{
    return 0;
}

static rt_err_t i2c_bus_control(struct rt_i2c_bus_device *bus,
                            rt_uint32_t cmd,
                            rt_uint32_t args)
{
    rt_err_t ret;
    struct hc_i2c * i2c;

    LOG_D("i2c_bus_control, cmd %d, args %d", cmd, args);
    i2c = rt_container_of(bus, struct hc_i2c, bus);
    ret = hc_i2c_init(i2c->I2Cx, args);

    return ret;
}

const struct rt_i2c_bus_device_ops ops = 
{
    master_xfer,
    slave_xfer,
    i2c_bus_control,
};

int rt_hw_i2c_init(void)
{
    rt_uint8_t i;
    rt_err_t ret = RT_EOK;
    
    for (i = 0; i < i2c_num; i++)
    {
        /* init i2c */
        i2c_obj[i].bus.ops = &ops;

        /* register i2c device */
        ret = rt_i2c_bus_device_register(&i2c_obj[i].bus, i2c_obj[i].name);
        RT_ASSERT(ret == RT_EOK);
    }
    return 0;
}
INIT_BOARD_EXPORT(rt_hw_i2c_init);

/*************** I2C test *****************/

//*********************************************************************0.66
const rt_uint8_t color13[]={
0xFF,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x41,0x41,0x41,0xE1,0xF1,0xF1,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xC1,0xE1,0xF1,0x31,0x11,0x31,
0xF1,0xE1,0xC1,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x81,0xE1,0xF1,0xF9,0xF9,0x01,
0x01,0x01,0x01,0x01,0x41,0x71,0x39,0x1F,0x4F,0x77,0x39,0x1F,0x0F,0x07,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xFF,
0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
0x00,0xFF,0xFF,0xFF,0x00,0x00,0x60,0x78,0x5C,0x47,0x43,0x40,0xFF,0xFF,0xFF,0x40,
0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xE0,0x00,0x00,
0x08,0x08,0xC8,0x2F,0x2F,0x2F,0xC8,0x08,0x08,0xC0,0x20,0x20,0x20,0xCE,0x0E,0x2E,
0xEE,0x00,0x20,0xE0,0x20,0x00,0x00,0x40,0x20,0x20,0x23,0xC7,0x0F,0x0C,0xC8,0x2C,
0x2F,0x27,0xC3,0x00,0x20,0xE0,0x20,0x20,0x40,0x80,0x08,0x88,0x4F,0x2F,0x2F,0x48,
0x88,0x00,0x00,0x60,0x20,0xE0,0x20,0x60,0x00,0x00,0xC0,0x20,0x20,0x20,0x60,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
0xFF,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xBF,0xA0,0x80,
0x80,0x80,0xB0,0xA8,0xA4,0xA2,0xA1,0x80,0x80,0x9C,0xA3,0xA2,0xA3,0x9C,0x80,0xA0,
0xB8,0xA7,0x87,0xB8,0xA0,0x80,0x80,0x90,0xA0,0xA1,0xA1,0x9E,0x80,0x80,0xB0,0xA8,
0xA4,0xA2,0xA1,0x80,0xA0,0xBF,0xA0,0xA0,0x90,0x8F,0x80,0x8F,0x90,0xA0,0xA0,0x90,
0x8F,0x80,0x80,0x80,0xA0,0xBF,0xA0,0x80,0x80,0x80,0xB0,0xA1,0xA2,0xA2,0x9C,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xFF
};

const rt_uint8_t color14[]={
0x00,0x20,0xA0,0x78,0x20,0xF8,0x20,0x00,0x00,0x00,0x10,0xF8,0x00,0x00,0x00,0x00,
0xF0,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0xF8,0x88,
0x88,0x88,0xFE,0x88,0x88,0x88,0x88,0xF8,0x00,0x00,0x20,0x10,0xF8,0x06,0x20,0x20,
0x7E,0x90,0x88,0x88,0x84,0xE0,0x00,0x00,0x00,0x00,0x00,0x80,0x7E,0x80,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xFE,0x92,0x92,0x92,0xF2,0x92,0x92,0x92,0x9E,0x80,0x80,
0x00,0x00,0x08,0x08,0x08,0xFE,0x08,0x08,0x08,0xFE,0x08,0x08,0x00,0x00,0x20,0x24,
0xA4,0xFC,0xA2,0x22,0x20,0xF8,0x08,0x08,0xF8,0x00,0x00,0x00,0xFE,0x02,0x4A,0x4A,
0xFA,0x4A,0xCA,0x4A,0x02,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x02,0x0F,0x02,0x0F,0x02,0x02,0x00,0x00,0x00,0x08,0x0F,0x08,0x00,0x00,0x00,
0x07,0x08,0x08,0x08,0x07,0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00,0x01,0x00,
0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x01,0x80,0x00,0x02,0x02,0x02,0x02,0x02,0x1F,
0x02,0x02,0x02,0x02,0x02,0x82,0x00,0x10,0x08,0x84,0x02,0x01,0x00,0x01,0x02,0x04,
0x08,0x18,0x08,0x00,0x00,0x1F,0x10,0x08,0x84,0x00,0x03,0x04,0x08,0x10,0x10,0x1C,
0x00,0x01,0x11,0x09,0x05,0x03,0x01,0x01,0x03,0x05,0x09,0x11,0x01,0x00,0x04,0x03,
0x00,0x1F,0x00,0x01,0x00,0x0F,0x04,0x04,0x07,0x00,0x00,0x00,0x1F,0x0A,0x0A,0x0A,
0x0B,0x0A,0x0A,0x0B,0x0A,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x20,0xE0,0x3C,0x20,0xE0,0x3C,0x20,0x00,0x00,0x08,0x08,0xFC,0x00,0x00,0x00,
0x00,0x00,0x38,0x04,0x04,0x04,0xC4,0x38,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,
0x00,0x00,0x00,0xFE,0x04,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x04,0xFE,0x04,0x00,
0x00,0x10,0x08,0x04,0xFE,0x01,0x01,0x08,0x88,0x3F,0x44,0x44,0x42,0x43,0x72,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x1F,0xE1,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xFF,0x49,0x49,0x49,0x49,0x79,0xC9,0x49,0x49,0x4F,0x40,0x40,0x00,
0x00,0x00,0x08,0x08,0x08,0x08,0xFF,0x08,0x08,0x08,0x08,0xFF,0x08,0x08,0x08,0x00,
0x00,0x00,0x12,0x12,0xD2,0xFE,0x91,0x11,0x11,0x00,0xFC,0x04,0x04,0x04,0xFC,0x00,
0x00,0x02,0x1F,0x02,0x02,0x1F,0x02,0x02,0x00,0x00,0x10,0x10,0x1F,0x10,0x10,0x00,
0x00,0x00,0x18,0x14,0x12,0x11,0x10,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,
0x00,0x00,0x00,0x03,0x01,0x01,0x01,0x01,0x7F,0x01,0x01,0x01,0x01,0x03,0x00,0x00,
0x00,0x00,0x02,0x02,0x02,0x02,0x02,0x02,0x7F,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
0x00,0x00,0x20,0x10,0x08,0x06,0x01,0x00,0x00,0x00,0x03,0x06,0x0C,0x18,0x30,0x10,
0x00,0x00,0x00,0x7F,0x20,0x10,0x08,0x00,0x00,0x01,0x06,0x08,0x10,0x20,0x78,0x00,
0x00,0x01,0x01,0x41,0x21,0x19,0x0F,0x05,0x01,0x01,0x03,0x05,0x19,0x71,0x21,0x01,
0x00,0x08,0x04,0x03,0x00,0x7F,0x00,0x07,0x02,0x00,0x1F,0x08,0x08,0x08,0x1F,0x00
};

struct rt_i2c_bus_device *i2c_bus = RT_NULL;

void WriteCmd(rt_uint32_t cmd)
{
    rt_size_t len;
    rt_uint8_t buf[2] = {0x0, 0x0};
    buf[1] = cmd;
    struct rt_i2c_msg msg;
    msg.addr = 0x3C;
    msg.flags = RT_I2C_WR;
    msg.buf = buf;
    msg.len = 2;
    len = rt_i2c_transfer(i2c_bus, &msg, 1);
    if (len != 1)
    {
        rt_kprintf("rt i2c transfer failed, len %d\n", len);
    }
}

void Write_Data3(rt_uint32_t dat)
{
    rt_size_t len;
    rt_uint8_t buf[2] = {0x40, 0x0};
    buf[1] = dat;
    struct rt_i2c_msg msg;
    msg.addr = 0x3C;
    msg.flags = RT_I2C_WR;
    msg.buf = buf;
    msg.len = 2;
    len = rt_i2c_transfer(i2c_bus, &msg, 1);
    if (len != 1)
    {
        rt_kprintf("rt i2c transfer failed, len %d\n", len);
    }
}

void clr_oled(void)
{
	int i,j;
	for(j=0;j<4;j++)
	{
		WriteCmd(0x22);    //--set page1
		WriteCmd(j);       //--set start page
		WriteCmd(0x03);    //--set end page

 		for(i=0;i<128;i++)		  				//???????LCD
		{
			Write_Data3(0x00);
		}
	}
}
MSH_CMD_EXPORT(clr_oled, ...);

void pic13(void)
{
	int i,j;
	int k;
	k=0;
	for(j=0;j<4;j++)
	{
		WriteCmd(0x22);    //--set page1
		WriteCmd(j);       //--set start page
		WriteCmd(0x03);    //--set end page

 		for(i=0;i<128;i++)		  				//???????LCD
		{
			Write_Data3(color13[k]);
			k=k+1;
		
		}
	}
}
MSH_CMD_EXPORT(pic13, ...);

void pic14(void)
{
	int i,j;
	int k;
	k=0;
	for(j=0;j<4;j++)
	{
		WriteCmd(0x22);    //--set page1
		WriteCmd(j);       //--set start page
		WriteCmd(0x03);    //--set end page

 		for(i=0;i<128;i++)		  				//???????LCD
		{
			Write_Data3(color14[k]);
			k=k+1;
		
		}
	}
}
MSH_CMD_EXPORT(pic14, ...);

void i2c_test(void)
{
    rt_err_t ret;

    if (i2c_bus == RT_NULL)
    {
        i2c_bus = rt_i2c_bus_device_find("i2c2");
        if (i2c_bus == RT_NULL)
        {
            rt_kprintf("Can not find i2c2\n");
            return;
        }
        ret = rt_i2c_control(i2c_bus, 0, 400000ul);
        if (ret != RT_EOK)
        {
            rt_kprintf("rt i2c control failed\n");
            return;
        }
    }

    WriteCmd(0xae);	//--turn off oled panel
    WriteCmd(0x00);	//--set low column address
    WriteCmd(0x10);	//--set high column address
    WriteCmd(0x00);	//--set start line address
    WriteCmd(0xb0);	//--set page address
    WriteCmd(0x81);	//--set contrast control register
    WriteCmd(0xff);
    WriteCmd(0xa1);	//--set segment re-map 127 to 0   a0:0 to seg127
    WriteCmd(0xa6);	//--set normal display
    WriteCmd(0xc8);	//--set com(N-1)to com0  c0:com0 to com(N-1)
    WriteCmd(0xa8);	//--set multiples ratio(1to64)
    WriteCmd(0x1f);	//--1/64 duty
    WriteCmd(0xd3);	//--set display offset
    WriteCmd(0x00);	//--not offset
    WriteCmd(0xd5);	//--set display clock divide ratio/oscillator frequency
    WriteCmd(0x80);	//--set divide ratio
    WriteCmd(0xd9);	//--set pre-charge period
    WriteCmd(0x04);
    WriteCmd(0xda);	//--set com pins hardware configuration
    WriteCmd(0x00);
    WriteCmd(0xdb);	//--set vcomh
    WriteCmd(0x30);
    WriteCmd(0x8d);	//--set chare pump enable/disable
    WriteCmd(0x14);	//--set(0x10) disable
    WriteCmd(0xaf);	//--turn on oled panel
}
MSH_CMD_EXPORT(i2c_test, ...);

#define EE_PAGESIZE 8
#define EEPROM_ADDR (0xA0 >> 1)

struct rt_i2c_bus_device *i2c_bus_eeprom = RT_NULL;

rt_err_t eeprom_write(rt_uint16_t addr, rt_uint8_t *buf, rt_uint32_t len)
{
    rt_size_t size;
    rt_uint8_t addr_buf;
    rt_uint32_t wrlen;

    do {
        wrlen = EE_PAGESIZE - addr % EE_PAGESIZE;
        if (wrlen > len) wrlen = len;

        rt_kprintf("addr=%d, wrlen=%d\n", addr, wrlen);

        addr_buf = (addr)&0xFF;

        size = rt_i2c_master_send(i2c_bus_eeprom, EEPROM_ADDR, RT_I2C_WR | RT_I2C_NO_STOP, &addr_buf, 1); /* fixed: no stop iic */
        if (size != 1)
        {
            rt_kprintf("eeprom_write: write addr failed, size is:%d\n", size);
            return -RT_ERROR;
        }

        size = rt_i2c_master_send(i2c_bus_eeprom, EEPROM_ADDR, RT_I2C_WR | RT_I2C_NO_START, buf, wrlen); /* fixed: no restart iic */
        if (size != wrlen)
        {
            rt_kprintf("eeprom_write: write buf failed, size=%d\n", addr_buf, size);
            return -RT_ERROR;
        }
        buf  += wrlen;
        addr += wrlen;
        len  -= wrlen;
        rt_thread_mdelay(5);
    } while (len);

    return RT_EOK;
}

rt_err_t eeprom_read(rt_uint16_t addr, rt_uint8_t *buf, rt_uint32_t len)
{
    rt_size_t size;
    rt_uint8_t addr_buf;
    
    addr_buf = addr;

    size = rt_i2c_master_send(i2c_bus_eeprom, EEPROM_ADDR, RT_I2C_WR, &addr_buf, 1);
    if (size != 1)
    {
        rt_kprintf("eeprom_read: write buf failed, size is:%d\n", size);
        return -RT_ERROR;
    }

    size = rt_i2c_master_recv(i2c_bus_eeprom, EEPROM_ADDR, RT_I2C_RD, buf, len);
    if (size != len)
    {
        rt_kprintf("eeprom_read: write buf failed, size is:%d\n", size);
        return -RT_ERROR;
    }

    return RT_EOK;
}

rt_uint8_t wrbuf[2048];
rt_uint8_t rdbuf[2048] = {0};

static int a = 1;

int ee_test(void)
{
    rt_err_t ret;


    if (i2c_bus_eeprom == RT_NULL)
    {
        i2c_bus_eeprom = rt_i2c_bus_device_find("i2c1");
        if (i2c_bus_eeprom == RT_NULL)
        {
            rt_kprintf("Can not find i2c1\n");
            return -1;
        }
        ret = rt_i2c_control(i2c_bus_eeprom, 0, 400000ul);
        if (ret != RT_EOK)
        {
            rt_kprintf("rt i2c1 control failed\n");
            return -1;
        }
    }

    rt_uint16_t addr = 0;
    rt_uint32_t length = 2048;
    
    rt_kprintf("a = %d\n",a);
    
    for (int i; i < length; i++)
    {
        wrbuf[i] = i + a;
    }
    
    a++;
    
    rt_kprintf("a = %d\n",a);

    rt_kprintf("eeprom write at %d:\n", addr);
    for(int i=0; i < length; i++)
    {
        rt_kprintf("%d ", wrbuf[i]);
    }
    rt_kprintf("\n");

    eeprom_write(addr, wrbuf, length);
    rt_thread_mdelay(5);
    
#if 0
    
    ////////////////////////////////////
    eeprom_read(addr , rdbuf, length);

    rt_kprintf("eeprom read at %d:\n", addr);
    for(int i=0; i < length; i++)
    {
        rt_kprintf("%d ", rdbuf[i]);
    }
    rt_kprintf("\n");
    
#else

    for (int i = 0; i < length; i++)
    {
        ////////////////////////////////////
        eeprom_read(i, rdbuf, length - i);

        rt_kprintf("eeprom read at %d:\n", i);
        for(int j=0; j<(length - i); j++)
        {
            rt_kprintf("%d ", rdbuf[j]);
        }
        rt_kprintf("\n");
    }
#endif

    return 0;
}
MSH_CMD_EXPORT(ee_test, test eeprom read and write);

/***************************************************/
static en_result_t I2C_Master_Transmit(uint16_t u16DevAddr, uint8_t *pu8TxData, uint32_t u32Size, uint32_t u32TimeOut)
{
    en_result_t enRet;
    I2C_Cmd(M4_I2C1, Enable);

    I2C_SoftwareResetCmd(M4_I2C1, Enable);
    I2C_SoftwareResetCmd(M4_I2C1, Disable);
    enRet = I2C_Start(M4_I2C1,u32TimeOut);
    if(Ok == enRet)
    {
        enRet = I2C_TransAddr(M4_I2C1, (uint8_t)u16DevAddr, I2CDirTrans, u32TimeOut);


        if(Ok == enRet)
        {
            enRet = I2C_TransData(M4_I2C1, pu8TxData, u32Size,u32TimeOut);
        }
    }

    I2C_Stop(M4_I2C1,u32TimeOut);
    I2C_Cmd(M4_I2C1, Disable);

    return enRet;
}

static en_result_t I2C_Master_Receive(uint16_t u16DevAddr, uint8_t *pu8RxData, uint32_t u32Size, uint32_t u32TimeOut)
{
    en_result_t enRet;

    I2C_Cmd(M4_I2C1, Enable);
    I2C_SoftwareResetCmd(M4_I2C1, Enable);
    I2C_SoftwareResetCmd(M4_I2C1, Disable);
    enRet = I2C_Start(M4_I2C1,u32TimeOut);
    if(Ok == enRet)
    {
        if(1ul == u32Size)
        {
            I2C_AckConfig(M4_I2C1, I2c_NACK);
        }
        enRet = I2C_TransAddr(M4_I2C1, (uint8_t)u16DevAddr, I2CDirReceive, u32TimeOut);

        if(Ok == enRet)
        {

            enRet = I2C_MasterDataReceiveAndStop(M4_I2C1, pu8RxData, u32Size, u32TimeOut);
        }

        I2C_AckConfig(M4_I2C1, I2c_ACK);
    }

    if(Ok != enRet)
    {
        I2C_Stop(M4_I2C1,u32TimeOut);
    }
    I2C_Cmd(M4_I2C1, Disable);
    return enRet;
}

static en_result_t Master_Initialize(void)
{
    en_result_t enRet;
    stc_i2c_init_t stcI2cInit;
    float32_t fErr;

    I2C_DeInit(M4_I2C1);

    MEM_ZERO_STRUCT(stcI2cInit);
    stcI2cInit.u32ClockDiv = I2C_CLK_DIV2;
    stcI2cInit.u32Baudrate = 400000;
    stcI2cInit.u32SclTime = 0ul;
    enRet = I2C_Init(M4_I2C1, &stcI2cInit, &fErr);

    I2C_BusWaitCmd(M4_I2C1, Enable);

    return enRet;
}

void i2c_bear(void)
{
    en_result_t enRet;
    uint8_t u8TxBuf[9] = {0x00, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
    uint8_t u8RxBuf[8] = {0x0};
    uint8_t addr = 0x0;
    
    PORT_SetFunc(PortC, Pin04, Func_I2c1_Scl, Disable);
    PORT_SetFunc(PortC, Pin05, Func_I2c1_Sda, Disable);

    /* Enable I2C Peripheral*/
    PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_I2C1, Enable);
    /* Initialize I2C peripheral and enable function*/
    Master_Initialize();

    /*write one data*/
    enRet = I2C_Master_Transmit(EEPROM_ADDR, u8TxBuf, 9, TIMEOUT);
    if (enRet != Ok)
    {
        rt_kprintf("I2C_Master_Receive falied enRet %d\n", enRet);
    }
    
    rt_thread_mdelay(5);
    
    
    /*random read one data*/
    enRet = I2C_Master_Transmit(EEPROM_ADDR, &addr, 1, TIMEOUT);
    if (enRet != Ok)
    {
        rt_kprintf("I2C_Master_Receive falied enRet %d\n", enRet);
    }
    
    rt_thread_mdelay(5);
    
    enRet = I2C_Master_Receive(EEPROM_ADDR, u8RxBuf, 8, TIMEOUT);
    if (enRet != Ok)
    {
        rt_kprintf("I2C_Master_Receive falied enRet %d\n", enRet);
    }
    for (int i = 0; i < 8; i++)
    {
        rt_kprintf("u8RxBuf[%d] 0x%x\n", i, u8RxBuf[i]);
    }
}
MSH_CMD_EXPORT(i2c_bear, ...);


#endif /* BSP_USING_I2C */
